﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BonsaiScrum.Core.Domain.Shared;

namespace BonsaiScrum.Core.Domain
{
    /// <summary>
    /// This is a development project. In Command Query Separation, we are only using this object
    /// to contain business rules. That is why there are not public properties. If you want to get
    /// an object to show business data, use an object from the Query namespace.
    /// </summary>
    public class Project : BaseEntity<Project>
    {
        private string _name;
        private string _description;
        private ProjectStatus _status;
        private IList<Story> _stories;
        private IList<Sprint> _sprints;
        private User _scrumMaster;

        public virtual void ChangeName(string newName)
        {
            if (string.IsNullOrEmpty(newName))
                throw new InvalidOperationException("Project name cannot be null or empty.");

            _name = newName;
        }

        protected Project() 
        {
            _status = ProjectStatus.Active;
            _stories = new List<Story>();
            _sprints = new List<Sprint>();
        }

        public Project(string name, string description, ScrumMaster scrumMaster) : this()
        {
            if (string.IsNullOrEmpty(name))
                throw new InvalidOperationException("A project must have a name that is not null or empty.");

            if (scrumMaster == null)
                throw new InvalidOperationException("A new project must have a scrum master.");
            
            _name = name;
            _description = description;
            _scrumMaster = scrumMaster.Actor;
        }

        public virtual void AssignScrumMaster(ScrumMaster scrumMaster)
        {
            if (scrumMaster == null)
                throw new InvalidOperationException("A project must have a scrum master that is not an Echthros.");

            _scrumMaster = scrumMaster.Actor;
        }
        
        protected internal virtual void Drop()
        {
            _status = ProjectStatus.Dropped;
        }

        public virtual Story AddNewStory(ScrumMaster scrumMaster, string storyDescription)
        {
            if (_scrumMaster.Equals(scrumMaster.Actor) || _scrumMaster.IsManager())
            {
                var story = new Story(storyDescription, this);
                _stories.Add(story);

                return story;
            }
            else
                throw new AuthorizationException(scrumMaster.Actor.UserName, typeof(ScrumMaster));
        }

        public virtual bool HasUncompletedTasks()
        {
            return _stories.Any(x => !x.AllTasksAreCompleted());
        }

        public virtual void AddTask(string description, Priority priority, User createdBy, int storyId)
        {
            var story = _stories.Where(x => x.Id.Equals(storyId)).SingleOrDefault();

            if (story == null)
                throw new ArgumentException("Story was not found for this project.");

            story.AddTask(description, priority, 2);
        }
    }
}
